home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 1998 September / Macworld (1998-09).dmg / Shareware World / Info / For Developers / MacZoop 1.8.3 / More Classes / Advanced Dialogs / ZAdvancedDialog.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-09  |  40.8 KB  |  1,634 lines  |  [TEXT/CWIE]

  1. /*************************************************************************************************
  2. *
  3. *
  4. *            MacZoop - "the framework for the rest of us"         
  5. *
  6. *
  7. *
  8. *            ZAdvancedDialog.cpp    -- a dialog box that can be extended with new types of items.
  9. *                                    this will handle list boxes without further subclassing.
  10. *
  11. *
  12. *            © 1997, Graham Cox
  13. *
  14. *
  15. *
  16. *************************************************************************************************/
  17.  
  18. #include    "ZAdvancedDialog.h"
  19. #include    "MacZoop.h"
  20. #include    "ZApplication.h"
  21. #include    "ZGrafState.h"
  22.  
  23. #include    <LowMem.h>
  24.  
  25. // note: if you don't have the extra dialog items stuff, comment out this include. The
  26. // code that makes use of it will be automatically compiled out.
  27.  
  28. #include    "ZExtraDialogItems.h"
  29.  
  30. // list object for dialog items:
  31.  
  32. #include    "ZObjectArray.cpp"
  33.  
  34. // global procedure is used in ZListDialogItem to handle searching lists for matching
  35. // user's keypresses to list items.
  36.  
  37. static pascal short    FindCellCompProc( Ptr dataA, Ptr dataB, short lenA, short lenB );
  38.  
  39. ListSearchUPP    gFindCellCompUPP = NewListSearchProc( FindCellCompProc );
  40.  
  41. // global commander 
  42.  
  43. extern ZCommander*        gCurHandler;
  44.  
  45.  
  46. // item objects:
  47. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  48.  
  49.  
  50. ZDialogItem::ZDialogItem( ZDialog* aDialog, short item )
  51.     : ZCommander( aDialog )
  52. {
  53.     short        iType;
  54.     
  55.     FailNIL( aDialog );
  56.     
  57.     id = item;
  58.     
  59.     // by default, items based on ZDialogItem cannot have the keyboard focus, and
  60.     // will behave accordingly. If you have an item that can have the keyboard focus,
  61.     // set this member to TRUE in your constructor. See ZListDialogItem for example.
  62.     
  63.     canBeHandler = FALSE;
  64.     isHandler = FALSE;
  65.     
  66.     // get initial info from the dialog manager item
  67.     
  68.     GetDialogItem( aDialog->GetMacWindow(), item, &iType, &iHand, &bounds );
  69.  
  70.     // convert the original dialog manager type into our more
  71.     // "sophisticated" types.
  72.     
  73.     enabled = ((iType & itemDisable) == 0);
  74.     iType &= 0x7F;
  75.     
  76.     switch ( iType )
  77.     {
  78.         case statText:
  79.             type = typeStaticText;
  80.             break;
  81.         case editText:
  82.             type = typeEditText;
  83.             break;
  84.         case iconItem:
  85.             type = typeIcon;
  86.             break;
  87.         case picItem:
  88.             type = typePicture;
  89.             break;
  90.         case ctrlItem + btnCtrl:
  91.             type = typeButton;
  92.             break;
  93.         case ctrlItem + chkCtrl:
  94.             type = typeCheckBox;
  95.             break;
  96.         case ctrlItem + radCtrl:
  97.             type = typeRadioButton;
  98.             break;
  99.         case ctrlItem + resCtrl:
  100.             type = typeResControl;
  101.             break;
  102.         case userItem:
  103.             type = typeUserItem;
  104.             break;
  105.     }
  106. }
  107.  
  108. /*--------------------------------***  DRAWBORDER  ***----------------------------------*/
  109. /*    
  110. draws the default outline used to indicate keyboard focus
  111. ----------------------------------------------------------------------------------------*/
  112.  
  113. void    ZDialogItem::DrawBorder( Boolean bState )
  114. {
  115.     ZDialog* zd = (ZDialog*) GetBoss();
  116.     
  117.     // border only drawn if owning window is active
  118.     
  119.     if ( zd->IsActive() || !bState )
  120.     {
  121.         zd->SetDefaultColours();
  122.         
  123.         Rect    r = bounds;
  124.         
  125.         InsetRect( &r, -3, -3 );
  126.         PenSize( 2, 2 );
  127.         
  128.         if ( bState )
  129.             PenMode( patOr );
  130.         else
  131.             PenMode( patBic );
  132.             
  133.         FrameRect( &r );
  134.         PenNormal();
  135.     }
  136. }
  137.  
  138. /*-------------------------------***  BECOMEHANDLER  ***--------------------------------*/
  139. /*    
  140. this item should become the command handler, or relinquish back to its boss if false. This
  141. allows this item to have the keyboard focus, and draws the border accordingly.
  142. ----------------------------------------------------------------------------------------*/
  143.  
  144. void    ZDialogItem::BecomeHandler( Boolean isBecoming )
  145. {
  146.     if (( isBecoming != isHandler) && canBeHandler )
  147.     {
  148.         ZAdvancedDialog*    zd = (ZAdvancedDialog*) GetBoss();
  149.         
  150.         // we are becoming the handler for the owning dialog, so switch its
  151.         // handler member to this. This is done via a couple of messages to
  152.         // the dialog, which, as its boss, will always receive them even if
  153.         // not explicitly told to do so.
  154.         
  155.         if ( isBecoming )
  156.             SendMessage( ItemNowHandler, NULL );
  157.         else
  158.             SendMessage( ItemNoLongerHandler, NULL );
  159.         
  160.         isHandler = isBecoming;
  161.         
  162.         // only draw the hilite border if we're not the only item that can be the
  163.         // handler. If this is the only one, then we're always it!
  164.         
  165.         if ( zd->HasMultipleFoci())
  166.         {
  167.             zd->Focus();
  168.             DrawBorder( isHandler );
  169.         }
  170.     }
  171. }
  172.  
  173. /*--------------------------------***  ADJUSTCURSOR  ***--------------------------------*/
  174. /*    
  175. set the cursor shape over this item (default sets arrow)
  176. ----------------------------------------------------------------------------------------*/
  177.  
  178. void    ZDialogItem::AdjustCursor( const Point where, const short modifiers )
  179. {
  180.     SetCursorShape( 0 );
  181. }
  182.  
  183.  
  184. void    ZDialogItem::SetUpFontAndColours()
  185. {
  186.     ZDialog*    zd = (ZDialog*) GetBoss();
  187.     
  188.     if ( zd->GetMacWindow() && IsColourPort( zd->GetMacWindow()))
  189.         zd->SetTEItemDataFromIctb( id, TRUE );
  190.     else
  191.         zd->SetDefaultColours();
  192. }
  193.  
  194. #pragma mark =============  ZListDialogItem  ==============
  195.  
  196. // listbox dialog item:
  197. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  198.  
  199.  
  200. ZListDialogItem::ZListDialogItem( ZDialog* aDialog, const short item  )
  201.     : ZDialogItem( aDialog, item )
  202. {
  203.     theList = NULL;
  204.     canBeHandler = TRUE;    // list boxes can handle keyboard focus
  205.     listResID = 0;
  206.     
  207.     // get the key threshold. This is double the delay time
  208.     // set by the user for "delay until repeat" in the global
  209.     // keyboard control panel, or two seconds, whichever is shorter.
  210.     
  211.     fThresh = MIN( 120, LMGetKeyThresh() * 2);
  212.     searchStr[0] = 0;
  213.     lastKeyTime = 0;
  214.     lastSel.h = lastSel.v = 0;
  215.     strListID = 0;
  216.     
  217.     fontSize = 0;
  218.     font = 0;
  219. }
  220.  
  221.  
  222. /*--------------------------------***  DESTRUCTOR  ***----------------------------------*/
  223.  
  224. ZListDialogItem::~ZListDialogItem()
  225. {
  226.     LDispose( theList );
  227. }
  228.  
  229. /*---------------------------------***  DRAWITEM  ***-----------------------------------*/
  230. /*    
  231.  
  232. draw this dialog item. This updates the list
  233. ----------------------------------------------------------------------------------------*/
  234.  
  235. void    ZListDialogItem::DrawItem()
  236. {
  237.     ZAdvancedDialog*    zd;
  238.     
  239.     zd = (ZAdvancedDialog*) GetBoss();
  240.     
  241.     // if we are using a font different to the window, set that now
  242.     
  243.     short    saveFont, saveSize;
  244.     
  245.     SetUpFontForList( &saveFont, &saveSize );
  246.  
  247. #if _ERASE_LIST_BOUNDS    
  248.     Rect ib = bounds;
  249.     
  250.     InsetRect( &ib, 1, 1 );
  251.     
  252.     if ((*theList)->vScroll )
  253.         ib.right -= kStdScrollbarWidth;
  254.         
  255.     if ((*theList)->hScroll )
  256.         ib.bottom -= kStdScrollbarWidth;
  257.     
  258.     EraseRect( &ib );
  259. #endif
  260.         
  261.     LUpdate( zd->GetMacWindow()->visRgn, theList );
  262.     PenNormal();
  263.     FrameRect( &bounds );
  264.  
  265.     // add greyscale effects if desired
  266.     
  267.     #ifdef _GREYSCALE_APPEARANCE
  268.     
  269.     zd->SetDefaultColours();
  270.     FrameGrayRect( &bounds );
  271.  
  272.     #endif
  273.     
  274.     // draw a border if we are the handler and the owner can have more than
  275.     // just this item as the keyboard focus
  276.     
  277.     if ( isHandler && zd->HasMultipleFoci())
  278.         DrawBorder( TRUE );
  279. }
  280.  
  281.  
  282. /*---------------------------------***  CLICKITEM  ***----------------------------------*/
  283. /*    
  284.  
  285. pass mouse clicks to the dialog item (the list, in this case)
  286. ----------------------------------------------------------------------------------------*/
  287.  
  288. void    ZListDialogItem::ClickItem( const Point where, const short modifiers )
  289. {
  290.     // the user clicked in this list box. If we are not already the handler, make
  291.     // sure that we are switched in. This will give us the keyboard focus and
  292.     // draw the hilited border if necessary
  293.     
  294.     Boolean    dblClick;
  295.     
  296.     if (! isHandler && canBeHandler)
  297.         BecomeHandler( TRUE );
  298.     
  299.     // if we are using a font different to the window, set that now
  300.     
  301.     short    saveFont, saveSize;
  302.     
  303.     SetUpFontForList( &saveFont, &saveSize );
  304.         
  305.     // now pass the click on to the list manager
  306.         
  307.     Cell a = { 0, 0 }, b;
  308.     
  309.     b = a;
  310.     
  311.     LGetSelect( TRUE, &a, theList );
  312.     dblClick = LClick( where, modifiers, theList );
  313.     LGetSelect( TRUE, &b, theList );
  314.     
  315.     // if the click resulted in a change to the selection in the list, send a message
  316.     // to tell anyone whose listening what the new cell is. This is automatically
  317.     // picked up by the owning dialog, which makes it very easy to respond to listbox
  318.     // clicks and do whatever you need to with the info.
  319.     
  320.     if ( DeltaPoint( a, b ))
  321.         SendMessage( newListItemSelected, &b );
  322.         
  323.     if ( dblClick )
  324.         SendMessage( listItemDoubleClicked, &b );
  325. }
  326.  
  327.  
  328. /*-------------------------------***  BECOMEHANDLER  ***--------------------------------*/
  329. /*    
  330. change activation state of list according to whether this has focus or not
  331. ----------------------------------------------------------------------------------------*/
  332.  
  333. void    ZListDialogItem::BecomeHandler( Boolean isBecoming )
  334. {
  335.     ZGrafState    zg;
  336.  
  337.     SetUpFontAndColours();
  338.     ZDialogItem::BecomeHandler( isBecoming );
  339.     
  340.     // we don't deactivate or activate the whole list, since the appearance isn't too
  341.     // great and is inconsistent with e.g. the Standard File Dialog. Instead we save
  342.     // the current hilited item and save and restore that.
  343.     
  344.     ActivateListItem( isHandler );    
  345. }
  346.  
  347.  
  348. /*-----------------------------------***  TYPE  ***-------------------------------------*/
  349. /*    
  350. when we have the keyboard focus, this will be called and we can use it to navigate
  351. around our list. This also selects cells according to what the user types. NOTE that
  352. this only works if the list is ordered alphabetically in the first place.
  353. ----------------------------------------------------------------------------------------*/
  354.  
  355. void    ZListDialogItem::Type( const char theKey, const short modifiers )
  356. {
  357.     Cell    curCell = { 0, 0 }, oldCell;
  358.     Rect    db = (*theList)->dataBounds;
  359.     
  360.     db.right--;
  361.     db.bottom--;
  362.     
  363.     // find the currently selected cell
  364.     
  365.     LGetSelect( TRUE, &curCell, theList );
  366.     oldCell = curCell;
  367.     
  368.     switch ( theKey )
  369.     {
  370.         case LEFT_ARROW_KEY:        // left arrow, move left if possible
  371.             curCell.h = MAX( db.left, curCell.h - 1 );
  372.             break;
  373.         
  374.         case RIGHT_ARROW_KEY:        // right arrow, move right if possible
  375.             curCell.h = MIN( db.right, curCell.h + 1 );
  376.             break;
  377.         
  378.         case UP_ARROW_KEY:            // up arrow, move up if possible
  379.             curCell.v = MAX( db.top, curCell.v - 1 );
  380.             break;
  381.         
  382.         case DOWN_ARROW_KEY:        // down arrow, move down if possible
  383.             curCell.v = MIN( db.bottom, curCell.v + 1 );
  384.             break;
  385.         
  386.         default:
  387.             
  388.             // handle letter typing to select items in list.            
  389.             
  390.             if (( theKey >= 'a' && theKey <= 'z' ) ||
  391.                 ( theKey >= 'A' && theKey <= 'Z' ) ||
  392.                 ( theKey >= '0' && theKey <= '9' ))
  393.             {
  394.                 long    theTime = TickCount();
  395.                 Cell    findCell = { 0, 0 };
  396.                 
  397.                 // time to start a new string yet?
  398.                 
  399.                 if ((theTime > lastKeyTime + fThresh) || (searchStr[0] > 12))
  400.                 {
  401.                     // start a new string
  402.                     
  403.                     searchStr[0] = 0;
  404.                 }
  405.                 lastKeyTime = theTime;
  406.                 
  407.                 // add typed chars to the search string
  408.                 
  409.                 searchStr[++searchStr[0]] = theKey;
  410.                 
  411.                 // find a cell that matches this
  412.                 
  413.                 if ( LSearch( &searchStr[1], searchStr[0], gFindCellCompUPP, &findCell, theList ))
  414.                 {
  415.                     // we found one, so make it the selected cell
  416.                     
  417.                     curCell = findCell;
  418.                 }
  419.             }
  420.             break;
  421.     }
  422.     
  423.     // turn off the old cell and hilite the new cell
  424.     
  425.     if ( DeltaPoint( curCell, oldCell ))
  426.     {
  427.         ZGrafState    zg;
  428.         
  429.         SetUpFontAndColours();
  430.         
  431.         LSetSelect( FALSE, oldCell, theList );
  432.         SelectCell( curCell );
  433.     }
  434.     
  435.     ZDialogItem::Type( theKey, modifiers );
  436. }
  437.  
  438.  
  439. /*---------------------------------***  INITITEM  ***-----------------------------------*/
  440. /*    
  441. pass pseudo-parameters to this item for action
  442. ----------------------------------------------------------------------------------------*/
  443.  
  444. void    ZListDialogItem::InitItem( const long param1, const long param2 )
  445. {
  446.     // initialises this item from the pseudo-parameter list. The parameter list consists of
  447.     // of up to two numbers, but only this knows what they mean! For lists, the first value
  448.     // identifies the resource ID of a STR# resource which we use to fill the list. The second
  449.     // is unused at present. NOTE that caller will pass 0 for missing parameters, so generally
  450.     // this value should be avoided as having a special meaning.
  451.     
  452.     short    numItems, i, p2;
  453.     Cell    aCell = { 0, 0 };
  454.     Handle    strListH;
  455.     Str255    temp;
  456.     
  457.     // make the mac list manager structures based on the template <param1>
  458.     
  459.     MakeMacList( param1 );
  460.     
  461.     // if the template specified a string list, ignore param2. If it didn't,
  462.     // param2 is the ID of the STR# resource to use. If everything was 0,
  463.     // then we don't add anything to the list, and the caller must do this.
  464.     
  465.     if ( strListID > 0 )
  466.         p2 = strListID;
  467.     else
  468.         p2 = param2;
  469.     
  470.     if ( p2 > 0 )
  471.     {
  472.         strListH = GetResource( 'STR#', p2 );
  473.         
  474.         if ( strListH )
  475.         {
  476.             // how many items in the list?
  477.             
  478.             numItems = **(short**) strListH;
  479.             
  480.             // add each string to the list
  481.             
  482.             LSetDrawingMode( FALSE, theList );
  483.             aCell.v = (*theList)->dataBounds.bottom;
  484.             
  485.             for (i = 1; i <= numItems; i++ )
  486.             {
  487.                 GetIndString( temp, p2, i );
  488.                 
  489.                 // append to the list
  490.                 
  491.                 aCell.v = LAddRow( 1, aCell.v + 1, theList );
  492.                 LSetCell( &temp[1], temp[0], aCell, theList );
  493.             }
  494.             
  495.             ReleaseResource( strListH );
  496.         }
  497.     }    
  498.     
  499.     // make the bounding box an exact number of cells high- this looks far neater
  500.     // and saves the user from having to worry about tweaking the item's bounds
  501.     // in the dialog template.
  502.     
  503.     short    cellHeight = (*theList)->cellSize.v;
  504.     short    adjustAmount;
  505.     Boolean    hasH, hasV;
  506.     
  507.     hasH = ((*theList)->hScroll != NULL);
  508.     hasV = ((*theList)->vScroll != NULL);
  509.     
  510.     adjustAmount = (bounds.bottom - bounds.top - (hasH? 17 : 2)) % cellHeight;
  511.     bounds.bottom -= adjustAmount;
  512.     
  513.     LSize( bounds.right - bounds.left - (hasV? 17 : 2),
  514.            bounds.bottom - bounds.top - (hasH? 17 : 2),
  515.            theList );
  516.     
  517.     // turn list drawing back on
  518.     
  519.     LSetDrawingMode( TRUE, theList );
  520. }
  521.  
  522.  
  523. /*-------------------------------***  MAKEMACLIST  ***----------------------------------*/
  524. /*    
  525. make the list manager list. This can be built either as a 1-column list (template == 0),
  526. or from a list template resource which is defined in the header.
  527. ----------------------------------------------------------------------------------------*/
  528.  
  529. void    ZListDialogItem::MakeMacList( const short listTemplateID )
  530. {
  531.     // make the list manager list. By default, the list is one column wide with no
  532.     // initial rows. It has a vertical scrollbar only, and the LDEF used is the standard
  533.     // system one which displays strings in chicago 12. If you supply a template resource
  534.     // the list can be built from that, giving full generality.
  535.     
  536.     ZDialog*            zd = (ZDialog*) GetBoss();
  537.     Rect                r, dataBounds = { 0, 0, 0, 1 };
  538.     Point                cellSize = { 0, 0 };
  539.     ListTemplateHdl        ltH;
  540.     Boolean                hasV = TRUE, hasH = FALSE, hasGrow = FALSE, isVis = TRUE;
  541.     short                procID = 0;
  542.     
  543.     // based on the original item's bounds
  544.     
  545.     listResID = listTemplateID;
  546.     r = bounds;
  547.     InsetRect( &r, 1, 1 );
  548.     
  549.     // obtain the template if any
  550.     
  551.     if ( listTemplateID != 0 )
  552.     {
  553.         ltH = ( ListTemplateHdl ) GetResource( kListTemplateResType, listTemplateID );
  554.     
  555.         if ( ltH )
  556.         {
  557.             // there is a template, so use that to define the list.
  558.         
  559.             dataBounds.right     = MAX((*ltH)->columns, 1);
  560.             dataBounds.bottom     = (*ltH)->rows;
  561.             procID                 = (*ltH)->procID;
  562.             hasV                 = (*ltH)->hasVertScroll;
  563.             hasH                 = (*ltH)->hasHorizScroll;
  564.             hasGrow             = (*ltH)->hasGrowBox;
  565.             isVis                 = (*ltH)->visible;
  566.             
  567.             // set other data members from the template
  568.             
  569.             canBeHandler         = (*ltH)->keyboardNav;
  570.             fontSize             = (*ltH)->fontSize;
  571.             strListID            = (*ltH)->stringsListID;
  572.             
  573.             GetFNum((*ltH)->fontName, &font );
  574.             
  575.             ReleaseResource((Handle) ltH );
  576.         }
  577.     }
  578.     
  579.     // tweak bounding box to allow for scrollbars we require
  580.     
  581.     if ( hasV || hasGrow )
  582.         r.right -= 15;
  583.         
  584.     if ( hasH || hasGrow )
  585.         r.bottom -= 15;
  586.         
  587.     // if the desired font is other than the default window font, set that
  588.     // now so that the cell size is calculated accordingly.
  589.     
  590.     short    saveFont, saveSize;
  591.     
  592.     SetUpFontForList( &saveFont, &saveSize );
  593.     
  594.     // make the List Manager list according to the template, or default
  595.     
  596.     theList = LNew( &r, &dataBounds,
  597.                     cellSize, procID,
  598.                     zd->GetMacWindow(),
  599.                     isVis, hasGrow, hasH, hasV );
  600.                     
  601.     FailNIL( theList );
  602.     LActivate( TRUE, theList );
  603.     ActivateListItem( FALSE );
  604.     
  605.     // but back font if we changed it
  606.     
  607.     if ( fontSize != 0 &&
  608.          font != 0 )
  609.     {
  610.         TextFont( saveFont );
  611.         TextSize( saveSize );
  612.     }
  613. }
  614.  
  615. /*----------------------------***  ACTIVATELISTITEM  ***--------------------------------*/
  616. /*    
  617. hilite current selection. Used instead of LActivate for showing state when focussed, etc.
  618. ----------------------------------------------------------------------------------------*/
  619.  
  620. void    ZListDialogItem::ActivateListItem( const Boolean state )
  621. {
  622.     short        saveFont, saveSize;
  623.     
  624.     SetUpFontForList( &saveFont, &saveSize );
  625.     
  626.     if ( state )
  627.         LSetSelect( TRUE, lastSel, theList );
  628.     else
  629.     {
  630.         lastSel.h = lastSel.v = 0;
  631.         LGetSelect(    TRUE, &lastSel, theList ); 
  632.         LSetSelect( FALSE, lastSel, theList );
  633.     }
  634. }
  635.  
  636.  
  637. /*---------------------------------***  ACTIVATE  ***-----------------------------------*/
  638. /*    
  639. owning window is becoming active/inactive. Handle hiliting accordingly.
  640. ----------------------------------------------------------------------------------------*/
  641.  
  642. void    ZListDialogItem::Activate( const Boolean isActive )
  643. {
  644.     ZAdvancedDialog* zd = (ZAdvancedDialog*) GetBoss();
  645.     
  646.     if ( isHandler && zd->HasMultipleFoci())
  647.         DrawBorder( isActive );
  648.         
  649.     ActivateListItem( isActive );
  650.     PenNormal();
  651. }
  652.  
  653.  
  654. /*-----------------------------***  SETUPFONTFORLIST  ***-------------------------------*/
  655. /*    
  656. if list is using font different to window, this set it up. Should be called before any
  657. list manager call. Returns existing font
  658. ----------------------------------------------------------------------------------------*/
  659.  
  660. void    ZListDialogItem::SetUpFontForList( short* curFont, short* curSize )
  661. {
  662.     if ( font != 0 &&
  663.          fontSize != 0 )
  664.     {
  665.         ZDialog*    zd = (ZDialog*) GetBoss();
  666.         
  667.         *curFont = zd->GetMacWindow()->txFont;
  668.         *curSize = zd->GetMacWindow()->txSize;
  669.         
  670.         zd->SetTEItemDataFromIctb( id, TRUE );
  671.         
  672.         TextFont( font );
  673.         TextSize( fontSize );
  674.     }
  675. }
  676.  
  677.  
  678. /*----------------------------------***  HILITE  ***------------------------------------*/
  679. /*    
  680. set visual hilite state of item to indicate active state, etc.
  681. ----------------------------------------------------------------------------------------*/
  682.  
  683. void    ZListDialogItem::Hilite( Boolean state )
  684. {
  685.     LActivate( state, theList );
  686. }
  687.  
  688.  
  689. /*-------------------------------***  APPENDSTRING  ***---------------------------------*/
  690. /*
  691. appends the passed string to the list. This is a convenience function for building lists
  692. on the fly programmatically. This also assumes a 1-column list.    
  693. ----------------------------------------------------------------------------------------*/
  694.  
  695. void    ZListDialogItem::AppendString( Str255 aString, Boolean drawIt )
  696. {
  697.     Cell    aCell = { 0, 0 };
  698.     
  699.     aCell.v = (*theList)->dataBounds.bottom;
  700.     
  701.     LSetDrawingMode( FALSE, theList );
  702.  
  703.     // append to the list
  704.         
  705.     aCell.v = LAddRow( 1, aCell.v + 1, theList );
  706.     LSetCell( &aString[1], aString[0], aCell, theList );
  707.     
  708.     LSetDrawingMode( TRUE, theList );
  709.     
  710.     if ( drawIt )
  711.         DrawItem();
  712. }
  713.  
  714.  
  715. /*------------------------------***  GETSELECTEDCELL  ***-------------------------------*/
  716. /*
  717. returns in <startingCell> the next selected cell after the initial <startingCell>. Set
  718. this to 0,0 to simply find the first selection, then call again to find subsequent ones
  719. if necessary. If nothing is selected, this returns -1,-1 in <startingCell>.
  720. ----------------------------------------------------------------------------------------*/
  721.  
  722. void    ZListDialogItem::GetSelectedCell( Cell* startingCell )
  723. {
  724.     if ( ! LGetSelect( TRUE, startingCell, theList ))
  725.     {
  726.         startingCell->h = -1;
  727.         startingCell->v = -1;
  728.     }
  729. }
  730.  
  731.  
  732. /*------------------------------***  GETCELLSTRING  ***---------------------------------*/
  733. /*
  734. if the cells contain strings, this returns a copy the string in <aStr> from the cell <aCell>.
  735. ----------------------------------------------------------------------------------------*/
  736.  
  737. void    ZListDialogItem::GetCellString( Cell aCell, Str255 aStr )
  738. {
  739.     short    dataLen = 255;
  740.     
  741.     LGetCell( &aStr[1], &dataLen, aCell, theList );
  742.     aStr[0] = dataLen;
  743. }
  744.  
  745.  
  746. /*------------------------------***  SETCELLSTRING  ***---------------------------------*/
  747. /*
  748. if the cells contain strings, this can be used to set the contents of any cell.
  749. ----------------------------------------------------------------------------------------*/
  750.  
  751. void    ZListDialogItem::SetCellString( Cell aCell, Str255 aStr )
  752. {
  753.     LSetCell( &aStr[1], aStr[0], aCell, theList );
  754. }
  755.  
  756.  
  757. /*-----------------------------***  RESETANDCLEARLIST  ***------------------------------*/
  758. /*
  759. this deletes all of the data from the list, and restores the original rows and columns
  760. it had when first created. It also erases the list visually to prevent artifacts.
  761. ----------------------------------------------------------------------------------------*/
  762.  
  763. void    ZListDialogItem::ResetAndClearList()
  764. {
  765.     ZGrafState    zg;
  766.     
  767.     SetUpFontAndColours();
  768.     
  769.     LSetDrawingMode( TRUE, theList );
  770.     LDelColumn( 0, 0, theList );
  771.     LDelRow( 0, 0, theList );
  772.     
  773.     // the original number of rows/columns must be restored by re-reading the original
  774.     // 'LIST' resource, or if not present, by assuming a 1-column list.
  775.     
  776.     ListTemplateHdl        ltH;
  777.     Rect                db = { 0, 0, 0, 0 };
  778.     
  779.     ltH = ( ListTemplateHdl ) GetResource( kListTemplateResType, listResID );
  780.     
  781.     if ( ltH )
  782.     {
  783.         db.right     = MAX((*ltH)->columns, 1);
  784.         db.bottom     = (*ltH)->rows;
  785.         
  786.         ReleaseResource((Handle) ltH );
  787.     }
  788.     else
  789.         db.right = 1;    
  790.         
  791.     // add columns/rows according to <db>
  792.     
  793.     LAddColumn( db.right, 0, theList );
  794.     
  795.     if ( db.bottom > 0 )
  796.         LAddRow( db.bottom, 0, theList );
  797. }
  798.  
  799.  
  800. /*--------------------------------***  SETCELLDATA  ***---------------------------------*/
  801. /*
  802. if the cells do not contain strings, use this method to set the contents of a cell
  803. ----------------------------------------------------------------------------------------*/
  804.  
  805. void    ZListDialogItem::SetCellData( Cell aCell, Ptr someBuf, short dataLen )
  806. {
  807.     LSetCell( someBuf, dataLen, aCell, theList );
  808. }
  809.  
  810.  
  811. /*--------------------------------***  GETCELLDATA  ***---------------------------------*/
  812. /*
  813. if the cells do not contain strings, use this method to get the contents of a cell
  814. ----------------------------------------------------------------------------------------*/
  815.  
  816. void    ZListDialogItem::GetCellData( Cell aCell, Ptr someBuf, short* dataLen )
  817. {
  818.     LGetCell( someBuf, dataLen, aCell, theList );
  819. }
  820.  
  821.  
  822. /*-------------------------------***  ENABLEDRAWING  ***--------------------------------*/
  823. /*
  824. turn on list drawing
  825. ----------------------------------------------------------------------------------------*/
  826.  
  827. void    ZListDialogItem::EnableDrawing()
  828. {
  829.     LSetDrawingMode( TRUE, theList );
  830. }
  831.  
  832.  
  833. /*------------------------------***  DISABLEDRAWING  ***--------------------------------*/
  834. /*
  835. turn off list drawing
  836. ----------------------------------------------------------------------------------------*/
  837.  
  838. void    ZListDialogItem::DisableDrawing()
  839. {
  840.     LSetDrawingMode( FALSE, theList );
  841. }
  842.  
  843. /*--------------------------------***  SELECTCELL  ***----------------------------------*/
  844. /*
  845. select the cell, deselecting all others. Autoscrolls to show the cell if drawing on.
  846. ----------------------------------------------------------------------------------------*/
  847.  
  848. void    ZListDialogItem::SelectCell( Cell aCell )
  849. {
  850.     Cell         curCell = { 0, 0 };
  851.     Boolean        noSel;
  852.     
  853.     noSel = ! LGetSelect( TRUE, &curCell, theList );
  854.     
  855.     if ( aCell.h != curCell.h ||
  856.          aCell.v != curCell.v ||
  857.          noSel )
  858.     {
  859.         ZGrafState    zg;
  860.         
  861.         short    saveFont, saveSize;
  862.         
  863.         SetUpFontForList( &saveFont, &saveSize );
  864.         if ( ! noSel )
  865.             LSetSelect( FALSE, curCell, theList );
  866.         
  867.         LSetSelect( TRUE, aCell, theList );
  868.         lastSel = aCell;
  869.         
  870.         // tell listeners which cell we just selected
  871.         
  872.         SendMessage( newListItemSelected, &aCell );
  873.     }
  874.     LAutoScroll( theList );
  875. }
  876.  
  877.  
  878. #pragma mark ============  FindCellCompProc  ==============
  879.  
  880. /*----------------------------***  FindCellCompProc  ***--------------------------------*/
  881. /*    
  882. used to locate suitable cells when typing in a list box
  883. ----------------------------------------------------------------------------------------*/
  884.  
  885. static pascal short    FindCellCompProc( Ptr dataA, Ptr dataB, short lenA, short lenB )
  886. {
  887.     short    result = 1;
  888.     
  889.     if ( lenA > 0 )
  890.     {
  891.         if ( IUMagIDString( dataA, dataB, lenA, lenB ) == 0 )
  892.             result = 0;
  893.         else
  894.         {
  895.             if ( IUMagString( dataA, dataB, lenA, lenB ) == 1)
  896.                 result = 0;
  897.         }    
  898.     }
  899.     
  900.     return result;
  901. }
  902.  
  903. #pragma mark ============  ZAdvancedDialog  ==============
  904.  
  905. // the dialog:
  906. /*--------------------------------***  CONSTRUCTOR  ***---------------------------------*/
  907.  
  908. ZAdvancedDialog::ZAdvancedDialog( ZCommander* aBoss, const short dialogID )
  909.     : ZDialog( aBoss, dialogID )
  910. {
  911.     itsItems = NULL;    // no special items initially
  912.     curHandler = NULL;    // interpreted to mean "this", if NULL
  913.     focusItem = 0;        // no object item has the keyboard focus
  914. }
  915.  
  916.  
  917. /*---------------------------------***  DESTRUCTOR  ***---------------------------------*/
  918.  
  919. ZAdvancedDialog::~ZAdvancedDialog()
  920. {
  921.     if ( itsItems )
  922.     {
  923.         itsItems->DisposeAll();
  924.         ForgetObject( itsItems );
  925.     }
  926. }
  927.  
  928.  
  929. /*----------------------------------***  SETUP  ***-------------------------------------*/
  930. /*    
  931. set up the dialog, including special object items
  932. ----------------------------------------------------------------------------------------*/
  933.  
  934. void    ZAdvancedDialog::SetUp()
  935. {
  936.     ZDialog::SetUp();
  937.     
  938.     // once everything is built in the normal way, look for the magic static text items.
  939.     
  940.     Focus();
  941.     BuildItemList();    
  942.     
  943.     // if we only have a single focus, make sure it's selected by default! Otherwise we
  944.     // rely on the inherited SetUp to select the first editable text field. You can of
  945.     // course override this to make any desired item the initial focus.
  946.     
  947.     if ( ! HasMultipleFoci())
  948.         SelectNextFocus();
  949. }
  950.  
  951.  
  952. /*-------------------------------***  SELECTITEM  ***-----------------------------------*/
  953. /*    
  954. for your convenience, you can call this to switch to a particular edit field or other
  955. focussable item. Called internally by SelectNextFocus. If the item can't be a focus,
  956. this does nothing. This will redraw hilites, etc as needed.
  957. ----------------------------------------------------------------------------------------*/
  958.  
  959. void    ZAdvancedDialog::SelectItem( const short item )
  960. {
  961.     ZDialogItem*    di;
  962.     short            iType;
  963.     Handle            iHand;
  964.     Rect            iBox;
  965.     
  966.     di = GetObjectItem( item );
  967.     
  968.     if (di && di->CanBeHandler())
  969.         di->BecomeHandler( TRUE );
  970.     else
  971.     {
  972.         GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  973.         
  974.         if (( iType & 0x7F) == editText )
  975.         {
  976.             focusItem = 0;
  977.             ZDialog::SelectItem( item );
  978.             ClickItem( item );
  979.         }
  980.     }
  981. }
  982.  
  983.  
  984. /*--------------------------------***  DEACTIVATE  ***----------------------------------*/
  985. /*    
  986. deactivate focussed item if needed
  987. ----------------------------------------------------------------------------------------*/
  988.  
  989. void    ZAdvancedDialog::Deactivate()
  990. {
  991.     if ( focusItem != 0 )
  992.     {
  993.         // one of our items is the focus, not a text field, so handle the hilite
  994.         // here and return handled TRUE.
  995.         ZGrafState        zg;
  996.         ZDialogItem*    di = GetObjectItem( focusItem );
  997.         
  998.         if ( di )
  999.             di->Activate( FALSE );
  1000.     } 
  1001.     
  1002.     ZDialog::Deactivate();
  1003. }
  1004.  
  1005.  
  1006. /*---------------------------------***  ACTIVATE  ***-----------------------------------*/
  1007. /*    
  1008. activate focussed item if needed
  1009. ----------------------------------------------------------------------------------------*/
  1010.  
  1011. void    ZAdvancedDialog::Activate()
  1012. {
  1013.     if ( focusItem != 0 )
  1014.     {
  1015.         // one of our items is the focus, not a text field, so handle the hilite
  1016.         // here and return handled TRUE.
  1017.         ZGrafState        zg;
  1018.         ZDialogItem*    di = GetObjectItem( focusItem );
  1019.         
  1020.         if ( di )
  1021.             di->Activate( TRUE );
  1022.     }
  1023.     
  1024.     ZDialog::Activate();
  1025. }
  1026.  
  1027.  
  1028. /*--------------------------------***  GETHANDLER  ***----------------------------------*/
  1029. /*    
  1030. return active item if current, or this
  1031. ----------------------------------------------------------------------------------------*/
  1032.  
  1033. ZCommander*        ZAdvancedDialog::GetHandler()
  1034. {
  1035.     if ( curHandler )
  1036.         return curHandler;
  1037.     else
  1038.         return this;
  1039. }
  1040.  
  1041.  
  1042. /*--------------------------------***  CLICKITEM  ***-----------------------------------*/
  1043. /*    
  1044. pass clicks to dialog items
  1045. ----------------------------------------------------------------------------------------*/
  1046.  
  1047. void    ZAdvancedDialog::ClickItem( const short item )
  1048. {
  1049.     ZDialogItem*    di;
  1050.     
  1051.     di = GetObjectItem( item );
  1052.     
  1053.     if ( di && di->Enabled())
  1054.     {
  1055.         EventRecord    theEvent;
  1056.         ZGrafState    zg;
  1057.         
  1058.         // get the mouse and modifiers from the most recent event
  1059.         
  1060.         gApplication->GetCurrentEvent( &theEvent );
  1061.         GlobalToLocal( &theEvent.where );
  1062.         
  1063.         di->SetUpFontAndColours();
  1064.         di->ClickItem( theEvent.where, theEvent.modifiers );
  1065.     }
  1066.     else
  1067.     {
  1068.         // if the item is an edit text field, then we may need to divert the keyboard focus
  1069.         
  1070.         short    iType;
  1071.         Handle    iHand;
  1072.         Rect    iBox;
  1073.         
  1074.         GetDialogItem( macWindow, item, &iType, &iHand, &iBox );
  1075.         if ((iType & 0x7F) == editText )
  1076.             ReceiveMessage( NULL, ItemNowHandler, NULL );
  1077.             
  1078.         ZDialog::ClickItem( item );
  1079.     }
  1080. }
  1081.  
  1082.  
  1083. /*--------------------------------***  ENABLEITEM  ***----------------------------------*/
  1084. /*    
  1085. if item is 0, hilite all items
  1086. ----------------------------------------------------------------------------------------*/
  1087.  
  1088. void    ZAdvancedDialog::EnableItem( const short item )
  1089. {
  1090.     if ( item == 0 && itsItems )
  1091.     {
  1092.         ZDialogItem*    di = NULL;
  1093.         long            i;
  1094.     
  1095.         for( i = 1; i <= itsItems->CountItems(); i++ )
  1096.         {    
  1097.             di = itsItems->GetObject( i );
  1098.             
  1099.             if ( di )
  1100.                 di->Hilite( TRUE );
  1101.         }
  1102.     }
  1103.     
  1104.     ZDialog::EnableItem( item );
  1105. }
  1106.  
  1107.  
  1108. /*-------------------------------***  DISABLEITEM  ***----------------------------------*/
  1109. /*    
  1110. if item is 0, unhilite all items
  1111. ----------------------------------------------------------------------------------------*/
  1112.  
  1113. void    ZAdvancedDialog::DisableItem( const short item )
  1114. {
  1115.     if ( item == 0 && itsItems )
  1116.     {
  1117.         ZDialogItem*    di = NULL;
  1118.         long            i;
  1119.     
  1120.         for( i = 1; i <= itsItems->CountItems(); i++ )
  1121.         {    
  1122.             di = itsItems->GetObject( i );
  1123.             
  1124.             if ( di )
  1125.                 di->Hilite( FALSE );
  1126.         }
  1127.     }
  1128.     
  1129.     ZDialog::DisableItem( item );
  1130. }
  1131.  
  1132.  
  1133.  
  1134. /*-----------------------------------***  TYPE  ***-------------------------------------*/
  1135. /*    
  1136. handle keypresses. We need to do a little more than usual to handle tabbing, and passing
  1137. keystrokes to our custom items, if need be
  1138. ----------------------------------------------------------------------------------------*/
  1139.  
  1140. void    ZAdvancedDialog::Type( const char theKey, const short modifiers )
  1141. {
  1142.     Boolean        handled = FALSE;
  1143.     
  1144.     Focus();
  1145.     
  1146.     if ( theKey == TAB_KEY )        // tab
  1147.         handled = SelectNextFocus(( modifiers & shiftKey ) == shiftKey );
  1148.         
  1149.     if (! handled && ( curHandler == NULL ))
  1150.         ZDialog::Type( theKey, modifiers );
  1151. }
  1152.  
  1153.  
  1154. /*-------------------------------***  ADJUSTCURSOR  ***---------------------------------*/
  1155. /*    
  1156. if the cursor is over an object item, call its adjust cursor method
  1157. ----------------------------------------------------------------------------------------*/
  1158.  
  1159. void    ZAdvancedDialog::AdjustCursor( const Point mouse, const short modifiers )
  1160. {
  1161.     ZDialogItem*    di;
  1162.     
  1163.     di = FindObjectItem( mouse );
  1164.     
  1165.     if (di && di->Enabled())
  1166.         di->AdjustCursor( mouse, modifiers );
  1167.     else
  1168.         ZDialog::AdjustCursor( mouse, modifiers );
  1169. }
  1170.  
  1171.  
  1172. /*-------------------------------***  DRAWUSERITEM  ***---------------------------------*/
  1173. /*    
  1174. if the item is a dialog item object, ask it to draw, otherwise call the inherited method
  1175. ----------------------------------------------------------------------------------------*/
  1176.  
  1177. void    ZAdvancedDialog::DrawUserItem( const short item )
  1178. {
  1179.     ZDialogItem*    di;
  1180.     
  1181.     di = GetObjectItem( item );
  1182.     
  1183.     if ( di )
  1184.     {
  1185.         ZGrafState    zg;
  1186.         
  1187.         di->SetUpFontAndColours();
  1188.         di->DrawItem();
  1189.     }
  1190.     else
  1191.         ZDialog::DrawUserItem( item );
  1192. }
  1193.  
  1194.  
  1195. /*------------------------***  PARSESTATTEXTPSEUDOOBJECTS  ***--------------------------*/
  1196. /*    
  1197. Extract parameters from the static text string
  1198. ----------------------------------------------------------------------------------------*/
  1199.  
  1200. void    ZAdvancedDialog::ParseStatTextPseudoObjects( Str255 sText, long* typeParam, long* param1, long* param2 )
  1201. {
  1202.     // initially assume we won't find the magic string:
  1203.     
  1204.     *typeParam = 0;
  1205.     *param1 = 0;
  1206.     *param2 = 0;
  1207.     
  1208.     // is the string at least 6 chars long? It must consist of two dollar signs followed
  1209.     // by a four character object code. The additional parameters are optional.
  1210.     
  1211.     if ( sText[0] >= 6 )
  1212.     {
  1213.         // does it begin with two dollar signs?
  1214.         
  1215.         if (sText[1] == '$' &&
  1216.             sText[2] == '$' )
  1217.         {
  1218.             // yes, so extract the magic object code ( next 4 chars ). Note that heavyweight
  1219.             // frameworks sometimes do this sort of thing, but with the actual class name,
  1220.             // which they then pass to new_by_name, or somesuch. Though that allows greater
  1221.             // generality with less code, it is not really supported in a nice generic way
  1222.             // by all compilers, so we have opted for this simpler approach.
  1223.     
  1224.             *typeParam = *(long*) &sText[3];
  1225.             
  1226.             // any parameters? These should be comma delimited numbers
  1227.             
  1228.             char    pc = 0;
  1229.             char    i = 7;
  1230.             char    t;
  1231.             long    p;
  1232.             Str15    seg;
  1233.             
  1234.             while( i <= sText[0] )
  1235.             {
  1236.                 if ( sText[i++] == ',' )
  1237.                 {
  1238.                     t = i;
  1239.                     
  1240.                     // found a comma, search forward to next comma or
  1241.                     // end of string
  1242.                     
  1243.                     while(( sText[t] != ',' ) && ( t <= sText[0] )) t++;
  1244.                     
  1245.                     // extract part of string between two commas
  1246.                     
  1247.                     BlockMoveData( &sText[i], &seg[1], t - i );
  1248.                     seg[0] = t - i;
  1249.                     
  1250.                     StringToNum( seg, &p );
  1251.                     
  1252.                     i = t;
  1253.                     
  1254.                     // set parameter
  1255.                     
  1256.                     switch (pc++)
  1257.                     {
  1258.                         case 0:
  1259.                             *param1 = p;
  1260.                             break;
  1261.                         case 1:
  1262.                             *param2 = p;
  1263.                             break;
  1264.                     }
  1265.                 }
  1266.             }
  1267.         }
  1268.     }
  1269. }
  1270.  
  1271. /*-------------------------------***  BUILDITEMLIST  ***--------------------------------*/
  1272. /*    
  1273. builds the list of object items. This scans the dialog items looking for static text items.
  1274. If they contain the magic strings, the items are converted to user items and a relevant
  1275. object is created. To extend the types of objects this can make, override the
  1276. MakeObjectItem method
  1277. ----------------------------------------------------------------------------------------*/
  1278.  
  1279. void    ZAdvancedDialog::BuildItemList()
  1280. {
  1281.     short            n = CountDITL( macWindow );
  1282.     short            iType;
  1283.     long            p0, p1, p2;
  1284.     Handle            iHand;
  1285.     Rect            iBox;
  1286.     ZDialogItem*    di;
  1287.     Str255            iText;
  1288.     
  1289.     do
  1290.     {
  1291.         GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
  1292.         
  1293.         if ((iType & 0x7F) == statText)
  1294.         {
  1295.             GetDialogItemText( iHand, iText );
  1296.         
  1297.             // attempt to extract "magic" object parameters
  1298.             
  1299.             ParseStatTextPseudoObjects( iText, &p0, &p1, &p2 );
  1300.             
  1301.             // call the method to make the relevant object item from the code passed
  1302.             
  1303.             di = MakeObjectItem( p0, n );
  1304.             
  1305.             if ( di )
  1306.             {
  1307.                 // make sure the type code is set. The type set matches the original
  1308.                 // code, NOT the old constants defined in 1.7.1 and earlier.
  1309.                 ZGrafState    zg;
  1310.                 
  1311.                 di->SetType((ItemType) p0 );
  1312.                 
  1313.                 // if the item list hasn't been created yet, do it now
  1314.                 
  1315.                 if ( itsItems == NULL )
  1316.                     FailNIL( itsItems = new ZDialogItemList());
  1317.                     
  1318.                 // convert the static text item to a user item and set up its
  1319.                 // drawing proc.
  1320.                 
  1321.                 SetDialogItem( macWindow, n, userItem, (Handle) gUIVectorUPP, &iBox );
  1322.             
  1323.                 // add it to our list of items
  1324.                 
  1325.                 itsItems->AppendItem( di );
  1326.             
  1327.                 // now pass it any parameters we may have extracted
  1328.                 
  1329.                 di->InitItem( p1, p2 );
  1330.             }
  1331.         }
  1332.     }
  1333.     while( --n );
  1334. }
  1335.  
  1336.  
  1337. /*-----------------------------***  MAKEOBJECTITEM  ***---------------------------------*/
  1338. /*    
  1339. make an object to match the type sent from the stat text parameter. Override for
  1340. additional types. In fact, this is the only method you need to override to extend the
  1341. number of special objects this dialog can deal with.
  1342. ----------------------------------------------------------------------------------------*/
  1343.  
  1344. ZDialogItem*    ZAdvancedDialog::MakeObjectItem( const long aType, const short id )
  1345. {
  1346.     ZDialogItem*    di = NULL;
  1347.     
  1348.     switch ( aType )
  1349.     {
  1350.         case 'LIST':
  1351.             di = new ZListDialogItem( this, id );
  1352.             break;
  1353.         
  1354.         #ifdef __ZEXTRADIALOGITEMS__
  1355.         
  1356.         case 'LINE':
  1357.             di = new ZLineDialogItem( this, id );
  1358.             break;
  1359.         case 'ICLB':
  1360.             di = new ZIconListBox( this, id );
  1361.             break;
  1362.         case 'TEXT':
  1363.             di = new ZScrollingTextBox( this, id );
  1364.             break;
  1365.         
  1366.         #endif
  1367.     }
  1368.  
  1369.     return di;
  1370. }
  1371.  
  1372.  
  1373. /*---------------------------------***  FINDITEM  ***-----------------------------------*/
  1374. /*    
  1375. find which if any of the special items contains the point
  1376. ----------------------------------------------------------------------------------------*/
  1377.  
  1378. ZDialogItem*    ZAdvancedDialog::FindObjectItem( const Point where )
  1379. {
  1380.     ZDialogItem*    di = NULL;
  1381.     long            i;
  1382.     
  1383.     if ( itsItems )
  1384.     {
  1385.         for( i = 1; i <= itsItems->CountItems(); i++ )
  1386.         {    
  1387.             di = itsItems->GetObject( i );
  1388.             
  1389.             if (di && di->ContainsPoint( where ))
  1390.                 break;
  1391.  
  1392.             di = NULL;
  1393.         }
  1394.     }
  1395.     
  1396.     return di;
  1397. }
  1398.  
  1399.  
  1400. /*----------------------------------***  GETITEM  ***-----------------------------------*/
  1401. /*    
  1402. find an object item that has the ID passed, or NULL if none do.
  1403. ----------------------------------------------------------------------------------------*/
  1404.  
  1405. ZDialogItem*    ZAdvancedDialog::GetObjectItem( const short item )
  1406. {
  1407.     ZDialogItem*    di = NULL;
  1408.     long            i;
  1409.     
  1410.     if ( itsItems )
  1411.     {
  1412.         for( i = 1; i <= itsItems->CountItems(); i++ )
  1413.         {    
  1414.             di = itsItems->GetObject( i );
  1415.             
  1416.             if (di && di->GetID() == item )
  1417.                 break;
  1418.  
  1419.             di = NULL;
  1420.         }
  1421.     }
  1422.     
  1423.     return di;
  1424. }
  1425.  
  1426.  
  1427. /*------------------------------***  RECEIVEMESSAGE  ***--------------------------------*/
  1428. /*    
  1429. manipulate command chain in response to items coming into focus, etc.
  1430. ----------------------------------------------------------------------------------------*/
  1431.  
  1432. void    ZAdvancedDialog::ReceiveMessage( ZComrade* aSender, long aMessage, void* msgData )
  1433. {
  1434.     switch ( aMessage )
  1435.     {
  1436.         case ItemNowHandler:
  1437.             if ( aSender != curHandler )
  1438.             {
  1439.                 ZGrafState    zg;
  1440.                 
  1441.                 // tell current handler to stop being the handler!
  1442.                 
  1443.                 if ( curHandler )
  1444.                     curHandler->BecomeHandler( FALSE );
  1445.                     
  1446.                 curHandler = (ZDialogItem*) aSender;
  1447.                 
  1448.                 SetDefaultColours();
  1449.                 PenNormal();
  1450.                 
  1451.                 if ( curHandler )
  1452.                 {
  1453.                     // if there is a new item handler, make sure any editable text
  1454.                     // is not hilited
  1455.                     
  1456.                     HiliteDialogText( FALSE );
  1457.                     
  1458.                     focusItem = curHandler->GetID();
  1459.                     ((DialogPeek) macWindow)->editField = 0;
  1460.                 }
  1461.                 else
  1462.                 {
  1463.                     focusItem = 0;
  1464.                     HiliteDialogText( TRUE );
  1465.                 }
  1466.                 gCurHandler = GetHandler();
  1467.             }
  1468.             break;
  1469.         
  1470.         case ItemNoLongerHandler:
  1471.             curHandler = NULL;
  1472.             gCurHandler = GetHandler();
  1473.             break;
  1474.         
  1475.         default:
  1476.             ZDialog::ReceiveMessage( aSender, aMessage, msgData );
  1477.             break;
  1478.     }
  1479. }
  1480.  
  1481. /*-----------------------------***  HILITEDIALOGTEXT  ***-------------------------------*/
  1482. /*    
  1483. set up hiliting of edit text items in the dialog
  1484. ----------------------------------------------------------------------------------------*/
  1485.  
  1486. void    ZAdvancedDialog::HiliteDialogText( Boolean state )
  1487. {
  1488.     // turn on/off any editable text hiliting
  1489.     
  1490.     DialogPeek    dp = (DialogPeek) macWindow;
  1491.     
  1492.     if ( dp->textH )
  1493.     {
  1494.         ZGrafState    zg;
  1495.         
  1496.         SetTEItemDataFromIctb( dp->editField + 1, TRUE );
  1497.         
  1498.         if ( state )
  1499.             TEActivate( dp->textH );
  1500.         else
  1501.         {
  1502.             TEDeactivate( dp->textH );
  1503.             TESetSelect( 32767, 32767, dp->textH );
  1504.         }
  1505.     }
  1506. }
  1507.  
  1508.  
  1509. /*------------------------------***  SELECTNEXTFOCUS  ***-------------------------------*/
  1510. /*    
  1511. this is a cunning routine that allows us to sneak our extra focussable items into the
  1512. normal tabbing behaviour. Items that can have the focus are selected in turn each time
  1513. this is called. If the item is a standard edit field, this returns FALSE. If it's one
  1514. of ours, it returns TRUE. This boolean is passed back from the Filter function so that
  1515. it controls whether the dialog manager helps us out or not.
  1516. ----------------------------------------------------------------------------------------*/
  1517.  
  1518. Boolean        ZAdvancedDialog::SelectNextFocus( Boolean selectPrevious )
  1519. {
  1520.     DialogPeek        dp;
  1521.     short            curFocus, totalItems, n, iType, i;
  1522.     ZDialogItem*    di;
  1523.     Boolean            found = FALSE;
  1524.     Handle            iHand;
  1525.     Rect            iBox;
  1526.     
  1527.     dp = (DialogPeek) macWindow;
  1528.     totalItems = CountDITL( macWindow );
  1529.     
  1530.     // what item currently has the focus?
  1531.     
  1532.     if ((focusItem == 0) && HasEditFields())
  1533.         curFocus = dp->editField + 1;
  1534.     else
  1535.         curFocus = focusItem;
  1536.     
  1537.     if ( selectPrevious )
  1538.         n = curFocus - 1;
  1539.     else    
  1540.         n = curFocus + 1;
  1541.     
  1542.     i = 0;
  1543.         
  1544.     // find the next item to this one eligible to have the focus. This is either an
  1545.     // edit field or an object item that returns TRUE for CanBeHandler.
  1546.     
  1547.     do
  1548.     {
  1549.         // if we got to the end, start over at item 1
  1550.         
  1551.         if ( n < 1 )
  1552.             n = totalItems;
  1553.             
  1554.         if ( n > totalItems )
  1555.             n = 1;
  1556.         
  1557.         // is there an object at this position?
  1558.         
  1559.         di = GetObjectItem( n );
  1560.         
  1561.         if (di && di->CanBeHandler())
  1562.         {
  1563.             // yes, and it can be the focus!!
  1564.         
  1565.             found = TRUE;
  1566.             break;
  1567.         }
  1568.         else
  1569.         {
  1570.             // no. Is there an edit text item in this position?
  1571.         
  1572.             GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
  1573.             
  1574.             if (( iType & 0x7F ) == editText )
  1575.             {
  1576.                 // yes, so we'll let the Dialog Manager set the focus on this one
  1577.                 
  1578.                 found = TRUE;
  1579.                 break;
  1580.             }
  1581.         }
  1582.         
  1583.         if ( selectPrevious )
  1584.             n--;
  1585.         else
  1586.             n++;    // try the next item
  1587.     }
  1588.     while( !found && ( ++i < totalItems )); 
  1589.     
  1590.     // if we found an item to be focussed, set that focus now
  1591.     
  1592.     if ( found )
  1593.         SelectItem( n );
  1594.     
  1595.     // if an object, we handled it...
  1596.     
  1597.     return found;
  1598. }
  1599.  
  1600.  
  1601. /*------------------------------***  HASMULTIPLEFOCI  ***-------------------------------*/
  1602. /*    
  1603. this returns TRUE if this dialog has more than 1 item that can be the keyboard focus. 
  1604. ----------------------------------------------------------------------------------------*/
  1605.  
  1606. Boolean        ZAdvancedDialog::HasMultipleFoci()
  1607. {
  1608.     short            iType, fCount = 0, n;
  1609.     Handle            iHand;
  1610.     Rect            iBox;
  1611.     ZDialogItem*    di;
  1612.     
  1613.     n = CountDITL( macWindow );
  1614.     
  1615.     do
  1616.     {
  1617.         di = GetObjectItem( n );
  1618.         
  1619.         if (di && di->CanBeHandler())
  1620.             fCount++;
  1621.         else
  1622.         {
  1623.             GetDialogItem( macWindow, n, &iType, &iHand, &iBox );
  1624.         
  1625.             if (( iType & 0x7F ) == editText )
  1626.                 fCount++;
  1627.         }
  1628.     }
  1629.     while( --n );
  1630.     
  1631.     return ( fCount > 1 );
  1632. }
  1633.  
  1634.